package com.xxx.mch.service.impl;

import com.google.common.collect.Lists;
import com.xxx.mch.config.MchInterepter;
import com.xxx.mch.dao.DepartmentMapper;
import com.xxx.mch.dao.TaskScoreMapper;
import com.xxx.mch.dao.TaskScoreTemplateMapper;
import com.xxx.mch.dao.TotalScoreMapper;
import com.xxx.mch.dao.UsedScoreTemplateMapper;
import com.xxx.mch.dao.UserMapper;
import com.xxx.mch.domain.dto.AllowanceItem;
import com.xxx.mch.domain.dto.AllowanceScoreDto;
import com.xxx.mch.domain.dto.PersonalScoreDto;
import com.xxx.mch.domain.dto.TaskScoreTemplateDto;
import com.xxx.mch.domain.dto.UsedScoreTemplateDto;
import com.xxx.mch.domain.dto.UserDto;
import com.xxx.mch.domain.po.Department;
import com.xxx.mch.domain.po.SystemConfig;
import com.xxx.mch.domain.po.TaskScore;
import com.xxx.mch.domain.po.TaskScoreTemplate;
import com.xxx.mch.domain.po.TotalScore;
import com.xxx.mch.domain.po.User;
import com.xxx.mch.domain.request.ConfirmScoreRequest;
import com.xxx.mch.domain.request.QueryScoreRequest;
import com.xxx.mch.exception.BusinessException;
import com.xxx.mch.feign.HiveFeignClient;
import com.xxx.mch.service.SystemConfigService;
import com.xxx.mch.service.TaskScoreService;
import com.xxx.mch.service.TotalScoreService;
import com.xxx.mch.service.UsedScoreService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author FengHaixin
 * @description 一句话描述该文件的用途
 * @date 2020-02-25
 */
@Service
@Slf4j
public class UserServiceImpl
{
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Resource
    private TotalScoreMapper totalScoreMapper;

    @Autowired
    private TotalScoreService totalScoreService;

    @Autowired
    private TaskScoreService taskScoreService;

    @Autowired
    private UsedScoreService usedScoreService;

    @Resource
    private TaskScoreMapper taskScoreMapper;

    @Autowired
    private HiveFeignClient hiveFeignClient;

    @Resource
    private TaskScoreTemplateMapper taskScoreTemplateMapper;

    @Resource
    private UsedScoreTemplateMapper usedScoreTemplateMapper;

    @Autowired
    private SystemConfigService systemConfigService;


    @Transactional
    @Async
    public void insertOrUpdate()
    {
        List<Department> departmentList = departmentMapper.selectAll();
        for (Department dept : departmentList)
        {
            User exampleUser = new User();
            exampleUser.setDeptId(dept.getId());
            List<User> localUserList = userMapper.select(exampleUser);
            UserDto userDto = hiveFeignClient.getUserByOrganization(dept.getOrganizationCode(), 1000);
            log.info("同步用户: 部门-{}, 用户-{}", dept.getOrganizationName(), userDto.getResultList());
            if (!CollectionUtils.isEmpty(userDto.getResultList()))
            {
                List<User> userList = userDto.getResultList();
                if (!CollectionUtils.isEmpty(userList))
                {
                    for (User user : userList)
                    {
                        user.setDeptId(dept.getId());
                        User u = new User();
                        u.setUserCode(user.getUserCode());
                        Weekend<User> weekend = new Weekend<>(User.class);
                        WeekendCriteria<User, Object> criteria = weekend.weekendCriteria();
                        criteria.andEqualTo(User::getUserCode, user.getUserCode());
                        User old = userMapper.selectOneByExample(weekend);
                        if (Objects.nonNull(old))
                        {
                            user.setUid(old.getUid());
                            userMapper.updateByPrimaryKeySelective(user);
                        }
                        else
                        {
                            userMapper.insertSelective(user);
                        }
                        localUserList.remove(user);
                    }
                }
            }
            localUserList.stream().forEach(user -> {
                userMapper.deleteByPrimaryKey(user.getUid());
                log.info("删除用户-{}", user);
            });
        }
    }


    public List<User> getUserList(Integer deptId)
    {
        Weekend<User> weekend = new Weekend<>(User.class);
        WeekendCriteria<User, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(User::getDeptId, deptId);
        return userMapper.selectByExample(weekend);
    }


    public List<User> allUser()
    {
        return userMapper.selectAll();
    }


    public PersonalScoreDto scoreSummary(String uid, String month)
    {
        TotalScore totalScore = totalScoreService.queryTotalScore(uid, month);
        PersonalScoreDto personalScoreDto = new PersonalScoreDto();
        personalScoreDto.setUid(uid);
        if (Objects.isNull(totalScore))
        {
            return personalScoreDto;
        }
        BeanUtils.copyProperties(totalScore, personalScoreDto);
        personalScoreDto.setAccumulativePoints(totalScoreService.queryAccumulativePoints(uid));
        this.setTotalScore(personalScoreDto);
        return personalScoreDto;
    }


    public void confirmScore(ConfirmScoreRequest request)
    {
        TotalScore totalScore = totalScoreMapper.selectByPrimaryKey(request.getId());
        if (Objects.isNull(totalScore))
        {
            throw new BusinessException("不存在id：" + request.getId());
        }

        if (totalScore.getConfirm() != -1)
        {
            throw new BusinessException("已确认，不能再次确认");
        }
        if (totalScore.getUid().equals(MchInterepter.UID.get().getUid()))
        {
            BeanUtils.copyProperties(request, totalScore);
            totalScoreMapper.updateByPrimaryKeySelective(totalScore);
        }
        else
        {
            throw new BusinessException("不能确认他人得分");
        }
    }


    public List<AllowanceScoreDto> getAllowanceScore(String uid, String month)
    {
        QueryScoreRequest scoreRequest = new QueryScoreRequest();
        scoreRequest.setUid(uid);
        scoreRequest.setDate(month);
        List<AllowanceScoreDto> allowanceScoreDtos = this.getAllowanceScoreDtos(uid, month);
        allowanceScoreDtos.addAll(this.getUSedScoreList(uid, month));
        return allowanceScoreDtos;
    }


    private List<AllowanceScoreDto> getAllowanceScoreDtos(String uid, String month)
    {
        List<TaskScoreTemplateDto> templateDtoList = taskScoreService.getTaskTemplate(Lists.newArrayList(), 2, true, null);
        if (CollectionUtils.isEmpty(templateDtoList))
        {
            return Lists.newArrayList();
        }
        return templateDtoList.stream().map(templateDto -> {
            AllowanceScoreDto scoreDto = new AllowanceScoreDto();
            scoreDto.setName(templateDto.getName());
            Weekend<TaskScore> weekend = new Weekend<>(TaskScore.class);
            WeekendCriteria<TaskScore, Object> criteria = weekend.weekendCriteria();
            List<TaskScoreTemplateDto> children = templateDto.getChildren();
            List<Integer> idList = children.stream().map(TaskScoreTemplateDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(idList))
            {
                return scoreDto;
            }
            criteria.andIn(TaskScore::getTaskId, idList);
            criteria.andEqualTo(TaskScore::getUid, uid);
            criteria.andEqualTo(TaskScore::getScoreType, 1);
            criteria.andCondition("DATE_FORMAT(STR_TO_DATE(create_time,\"%Y-%m-%d %H:%i:%s\"), '%Y-%m')= '" + month + "'");
            List<TaskScore> taskScoreList = taskScoreMapper.selectByExample(weekend);
            if (CollectionUtils.isEmpty(taskScoreList))
            {
                return scoreDto;
            }
            List<AllowanceItem> allowanceItemList = taskScoreList.stream().map(taskScore -> {
                AllowanceItem item = new AllowanceItem();
                BeanUtils.copyProperties(taskScore, item);
                this.setScore(taskScore, item);
                return item;
            }).collect(Collectors.toList());
            scoreDto.setScoreList(allowanceItemList);
            return scoreDto;
        }).filter(scoreDto -> !CollectionUtils.isEmpty(scoreDto.getScoreList())).collect(Collectors.toList());
    }


    private List<AllowanceScoreDto> getUSedScoreList(String uid, String month)
    {
        List<UsedScoreTemplateDto> templateDtoList = usedScoreService.getTaskTemplate(Lists.newArrayList(), 2, true);
        if (CollectionUtils.isEmpty(templateDtoList))
        {
            return Lists.newArrayList();
        }
        return templateDtoList.stream().map(templateDto -> {
            AllowanceScoreDto scoreDto = new AllowanceScoreDto();
            scoreDto.setName(templateDto.getName());
            Weekend<TaskScore> weekend = new Weekend<>(TaskScore.class);
            WeekendCriteria<TaskScore, Object> criteria = weekend.weekendCriteria();
            List<UsedScoreTemplateDto> children = templateDto.getChildren();
            List<Integer> idList = children.stream().map(UsedScoreTemplateDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(idList))
            {
                return scoreDto;
            }
            criteria.andIn(TaskScore::getTaskId, idList);
            criteria.andEqualTo(TaskScore::getUid, uid);
            criteria.andEqualTo(TaskScore::getScoreType, 2);
            criteria.andCondition("DATE_FORMAT(STR_TO_DATE(create_time,\"%Y-%m-%d %H:%i:%s\"), '%Y-%m')= '" + month + "'");
            List<TaskScore> taskScoreList = taskScoreMapper.selectByExample(weekend);
            if (CollectionUtils.isEmpty(taskScoreList))
            {
                return scoreDto;
            }
            List<AllowanceItem> allowanceItemList = taskScoreList.stream().map(taskScore -> {
                AllowanceItem item = new AllowanceItem();
                BeanUtils.copyProperties(taskScore, item);
                return item;
            }).collect(Collectors.toList());
            scoreDto.setScoreList(allowanceItemList);
            return scoreDto;
        }).filter(scoreDto -> !CollectionUtils.isEmpty(scoreDto.getScoreList())).collect(Collectors.toList());
    }


    private void setScore(TaskScore taskScore, AllowanceItem item)
    {
        TaskScoreTemplate template = taskScoreTemplateMapper.selectByPrimaryKey(taskScore.getLevelId());
        if (Objects.isNull(template))
        {
            return;
        }
        item.setCompletedScore(
                taskScore.getCompletionTime().after(taskScore.getPlanCompletionTime()) ? BigDecimal.ZERO : template.getMaxScore());
        item.setOverdueScore(taskScore.getCompletionTime().after(taskScore.getPlanCompletionTime()) ?
                                     (Objects.isNull(template.getMinScore()) ? BigDecimal.ZERO : template.getMinScore()) :
                                     BigDecimal.ZERO);
    }


    private void setTotalScore(PersonalScoreDto personalScoreDto)
    {
        Map<String, SystemConfig> scoreWeight = systemConfigService.queryConfigByMenu("scoreWeight");
        BigDecimal determinationScoreWeight = scoreWeight.get("determinationScore").getValue().divide(new BigDecimal("100"), 2,
                                                                                                      RoundingMode.DOWN);
        BigDecimal allowanceScoreWeight = scoreWeight.get("allowanceScore").getValue().divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
        BigDecimal totalScore = personalScoreDto.getDeterminationScore().multiply(determinationScoreWeight).add(
                personalScoreDto.getAllowanceScore().multiply(allowanceScoreWeight)).add(personalScoreDto.getDeltaScore());
        personalScoreDto.setTotalScore(totalScore);
    }
}
